package org.xxpay.pay.channel.suile;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.xxpay.common.http.HttpRequestTemplate;
import org.xxpay.common.unify.AbstractPaymentConfig;
import org.xxpay.common.util.*;
import org.xxpay.common.util.sign.CertDescriptor;
import org.xxpay.common.util.sign.SignUtils;
import org.xxpay.common.util.sign.encrypt.Base64;
import org.xxpay.common.util.sign.encrypt.RSA;
import org.xxpay.core.common.Exception.ServiceException;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.constant.RetEnum;
import org.xxpay.core.entity.TransOrder;
import org.xxpay.pay.channel.BaseTrans;
import org.xxpay.pay.channel.sand.SandConfig;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.security.PrivateKey;
import java.util.Date;
import java.util.Map;

/**
 * @Package org.xxpay.pay.channel.sand
 * @Class: SandTransService.java
 * @Description:
 * @Author leo
 * @Date 2019/4/12 10:49
 * @Version
 **/
@Component
public class SuileTransService extends BaseTrans {
    private final static String logPrefix = "【随乐支付代付】";

    private static CertDescriptor certDescriptor;
    static {
        try {
            certDescriptor = new CertDescriptor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getOrderId(TransOrder transOrder) {
        String time = DateUtils.YYYYMMDDHHMMSSSSS.format(new Date());

        return "T" + time;
    }

    @Override
    public String getChannelName() {
        return SuileConfig.CHANNEL_NAME;
    }

    @Override
    public JSONObject trans(TransOrder transOrder) {
        _log.info("{}订单信息：{}", logPrefix, JSON.toJSONString(transOrder));
        SuileConfig suileConfig = new SuileConfig(getTransParam(transOrder));
        JSONObject bizParameters = getAgentpayParameters(suileConfig, transOrder);
        _log.info("{}请求参数：{}", logPrefix, bizParameters.toJSONString());
        // 请求参数转换成xml
        String originXml = XML.map2Xml(bizParameters, "message");
        JSONObject retObj = buildRetObj();
        try {
            String requestXml = getFinalXml(suileConfig, originXml);
            HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
            String originRes = requestTemplate.postForObject(suileConfig.getRequestUrl(), requestXml, String.class);
            _log.info("{}请求响应：{}", logPrefix, originRes);
            String [] resBase64s = originRes.split("\\|");
            String responseXml = new String(Base64.decode(resBase64s[0]), SignUtils.CHARSET_UTF8);
            Map<String, Object> resultMap = XML.xml2Map(responseXml);
            JSONObject origin = JSONObject.parseObject(JSON.toJSONString(resultMap));
            _log.info("{}请求响应明文：{}", logPrefix, origin);
            if(StringUtils.equals(origin.getString("respCode"), SuileConfig.RETURN_VALUE_SUCCESS)) {
                retObj.put("isSuccess", true);
                retObj.put("transOrderId", transOrder.getTransOrderId());
                retObj.put("channelOrderNo", "");
                retObj.putAll(origin);
                // 1. 处理中 2. 成功 3. 失败
                retObj.put("status", 1);
                return retObj;
            }
            retObj.put("isSuccess", false);
            retObj.put("status", 3);
            retObj.put("transOrderId", transOrder.getTransOrderId());
            retObj.put("channelErrCode", origin.getString("respCode"));
            retObj.put(PayConstant.RESULT_PARAM_ERRDES, "下单失败[" + origin.getString("info") + "]");
            retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
            return retObj;
        } catch(UnsupportedEncodingException e) {
            _log.error("{}请求数据Base64字符串转byte异常", logPrefix, e);
        } catch (Exception ex) {
            _log.error("{}请求下单异常", logPrefix, ex);
        }
        throw new ServiceException(RetEnum.RET_COMM_OPERATION_FAIL);
    }

    @Override
    public JSONObject query(TransOrder transOrder) {
        SuileConfig suileConfig = new SuileConfig(getTransParam(transOrder));
        JSONObject bizParameters = getAgentpayQueryParameters(suileConfig, transOrder);
        _log.info("{}查询请求参数：{}", logPrefix, bizParameters.toJSONString());
        // 请求参数转换成xml
        String originXml = XML.map2Xml(bizParameters, "message");
        JSONObject retObj = buildRetObj();
        try {
            String requestXml = getFinalXml(suileConfig, originXml);
            HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
            String originRes = requestTemplate.postForObject(suileConfig.getRequestUrl(), requestXml, String.class);
            _log.info("{}请求响应：{}", logPrefix, originRes);
            String [] resBase64s = originRes.split("\\|");
            String responseXml = new String(Base64.decode(resBase64s[0]), SignUtils.CHARSET_UTF8);
            Map<String, Object> resultMap = XML.xml2Map(responseXml);
            JSONObject origin = JSONObject.parseObject(JSON.toJSONString(resultMap));
            _log.info("{}请求响应明文：{}", logPrefix, origin);
            JSONObject detailObj = origin.getJSONArray("queryList").getJSONObject(0);
            if(StringUtils.equals(origin.getString("respCode"), SuileConfig.RETURN_VALUE_SUCCESS)) {
                retObj.put("isSuccess", true);
                retObj.put("transOrderId", transOrder.getTransOrderId());
                retObj.put("channelObj", origin);
                String respCode = detailObj.getString("respCode");
                if(StringUtils.equals(respCode, SuileConfig.RETURN_VALUE_SUCCESS)) {
                    retObj.put("status", 2); // 2表示成功
                } else if(StringUtils.equals(respCode, SuileConfig.RETURN_VALUE_HANDING)) {
                    retObj.put("status", 1); // 1处理中
                } else {
                    retObj.put("status", 3); // 3表示失败
                }
                return retObj;
            }
            retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
            retObj.put(PayConstant.RESULT_PARAM_ERRDES, String.format("code:%s,desc:%s", origin.getString("respCode"), origin.getString("respDesc")));
            retObj.put("channelErrCode", origin.getString("respCode"));
            retObj.put("isSuccess", false);
            return retObj;
        }catch (Exception ex) {
            _log.error("{}请求下单异常", logPrefix, ex);
        }
        throw new ServiceException(RetEnum.RET_COMM_OPERATION_FAIL);
    }

    @Override
    public JSONObject balance(String payParam) {
        SuileConfig suileConfig = new SuileConfig(payParam);
        JSONObject bizParameters = getAgentpayQueryBalanceParameters(suileConfig);
        _log.info("{}余额查询请求参数：{}", logPrefix, bizParameters.toJSONString());
        // 请求参数转换成xml
        String originXml = XML.map2Xml(bizParameters, "message");
        JSONObject retObj = buildRetObj();
        try {
            String requestXml = getFinalXml(suileConfig, originXml);
            HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
            String originRes = requestTemplate.postForObject(suileConfig.getRequestUrl(), requestXml, String.class);
            _log.info("{}请求响应：{}", logPrefix, originRes);
            String [] resBase64s = originRes.split("\\|");
            String responseXml = new String(Base64.decode(resBase64s[0]), SignUtils.CHARSET_UTF8);
            Map<String, Object> resultMap = XML.xml2Map(responseXml);
            JSONObject origin = JSONObject.parseObject(JSON.toJSONString(resultMap));
            _log.info("{}请求响应明文：{}", logPrefix, origin);
            if(origin.containsKey("balance")) {
                Long balance = origin.getLong("balance");
                BigDecimal bd = Util.conversionYuanAmount(Long.valueOf(balance));
                retObj.put("cashBalance", bd);
                retObj.put("payBalance", bd);
                return retObj;
            }
            retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
            retObj.put(PayConstant.RESULT_PARAM_ERRDES, "查询失败");
            return retObj;
        } catch (Exception ex) {
            _log.error("{}请求下单异常", logPrefix, ex);
        }
        throw new ServiceException(RetEnum.RET_COMM_OPERATION_FAIL);
    }

    private String getFinalXml(AbstractPaymentConfig config, String originXml) {
        try {
            String xmlBase64Sign = getSign(config, originXml);
            String xmlBase64 = Base64.encode(originXml.getBytes(SignUtils.CHARSET_UTF8));
            String requestXml = xmlBase64 + "|" + xmlBase64Sign;
            return requestXml;
        } catch (UnsupportedEncodingException e) {
            _log.error("{}请求数据Base64字符串转byte异常", logPrefix, e);
        }
        return null;
    }

    /**
     * RSA数字签名
     * @return
     */
    private String getSign(AbstractPaymentConfig config, String requestXml) {
        _log.info("{}请求xml：{}", logPrefix, requestXml);
        certDescriptor.initPrivateSignCert(config.getPrivateStorePath(), config.getPrivateStorePathPwd(), "PKCS12");

        PrivateKey privateKey = certDescriptor.getSignCertPrivateKey(config.getPrivateStorePathPwd());
        byte[] md5Bytes = DigestUtils.md5(requestXml);
        try {
            byte[] signBytes = RSA.sign(md5Bytes, privateKey, "SHA1withRSA");
            return Base64.encode(signBytes);
        } catch (Exception e) {
            _log.info("{}签名异常", logPrefix, e);
        }

        return null;
    }

    /**
     * 代付请求报文
     * @param config
     * @param transOrder
     * @return
     */
    private JSONObject getAgentpayParameters(AbstractPaymentConfig config, TransOrder transOrder) {
        JSONObject transferMap = new JSONObject();
        transferMap.put("application", config.getPayMode());
        transferMap.put("version", SuileConfig.DEFAULT_VERSION);
        transferMap.put("merchantId", config.getMchId());
        transferMap.put("tranId", transOrder.getTransOrderId());
        transferMap.put("timestamp", DateUtils.YYYYMMDDHHMMSS.format(new Date()));
        transferMap.put("receivePayNotifyUrl", payConfig.getNotifyTransUrl(getChannelName()));
        // 收付款类型 0 收款，1 付款
        transferMap.put("receivePayType", "1");
        //账户属性     0 对私，4 对公
        transferMap.put("accountProp", "0");
        //银行名称，对公必填
        transferMap.put("bankGeneralName", SandConfig.AP_PARAM_ACC_TYPE_VAL);
        transferMap.put("accNo", transOrder.getAccountNo());
        transferMap.put("accName", transOrder.getAccountName());
        transferMap.put("amount", transOrder.getAmount());
        // 证件类型  01 身份证，对私必填
        transferMap.put("credentialType", "01");
        // 证件号，对私必填, 默认填写
        transferMap.put("credentialNo", "330781198509072816");
        // 默认填写
        transferMap.put("tel", "13200000000");
        transferMap.put("summary", transOrder.getRemarkInfo());
        return  transferMap;
    }

    /**
     * 代付查询业务请求报文
     * @param config
     * @param transOrder
     * @return
     */
    private JSONObject getAgentpayQueryParameters(AbstractPaymentConfig config, TransOrder transOrder) {
        JSONObject tquery = new JSONObject();
        tquery.put("application", "ReceivePayQuery");
        tquery.put("version", SuileConfig.DEFAULT_VERSION);
        tquery.put("merchantId", config.getMchId());
        tquery.put("timestamp", DateUtils.YYYYMMDDHHMMSS.format(new Date()));
        tquery.put("queryTranId", transOrder.getTransOrderId());
        return tquery;
    }

    private JSONObject getAgentpayQueryBalanceParameters(AbstractPaymentConfig config) {
        JSONObject tquery = new JSONObject();
        tquery.put("version", SandConfig.AP_PARAMS_VERSION_VAL);
        tquery.put("application", "QueryBalance");
        tquery.put("merchantId", config.getMchId());
        return tquery;
    }

}
